#define _POSIX_SOURCE
#define _BSD_SOURCE

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "rngs.h"
#include <getopt.h>

#ifndef TEST_CASES
#define TEST_CASES 10000
#endif

#ifndef RAND_NUM
#define RAND_NUM 100
#endif

#ifndef SUPP
#define SUPP 10
#endif

int createGameState(struct gameState *state, int *handPos, int *choice1, int *choice2)
{
	int i, j;

	// Generate 2-4 players
	state->numPlayers = floor(Random() * (MAX_PLAYERS - 1)) + 2;
	state->whoseTurn = floor(Random() * state->numPlayers);

	state->numActions = floor(Random() * RAND_NUM);
	state->coins = floor(Random() * RAND_NUM);
	state->playedCardCount = floor(Random() * RAND_NUM);

	for (i = 0; i < state->numPlayers; i++) {
		state->handCount[i] = floor(Random() * RAND_NUM);
		state->deckCount[i] = floor(Random() * (RAND_NUM - 4)) + 5;
		state->discardCount[i] = floor(Random() * RAND_NUM);

		for (j = 0; j < state->handCount[i]; j++) {
			state->hand[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->deckCount[i]; j++) {
			state->deck[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->discardCount[i]; j++) {
			state->discard[i][j] = floor(Random() * (treasure_map + 1));
		}
	}

	// Make sure current player has the card to test
	if (state->handCount[state->whoseTurn] <= 0) {
		state->hand[state->whoseTurn][0] = minion;
		state->handCount[state->whoseTurn] += 1;
		*handPos = 0;
	} else {
		*handPos = floor(Random() * state->handCount[state->whoseTurn]);
		state->hand[state->whoseTurn][*handPos] = minion;
	}

	//Choices are either 0 or 1
	*choice1 = floor(Random() * 2);
	*choice2 = floor(Random() * 2);
	
	return 0;
}

int test(struct gameState *state, int handPos, int choice1, int choice2)
{
	int i, j, handCount;
	struct gameState pre;

	memcpy(&pre, state, sizeof(struct gameState));

	cardEffect(minion, choice1, choice2, -1, state, handPos, NULL);

	// Set pre to expected values
	pre.numActions += 1;

	if (choice1) {
		pre.coins += 2;
	
	} else if (choice2) {
		discardCard(handPos, pre.whoseTurn, &pre, 0);

		handCount = pre.handCount[pre.whoseTurn];

		for (i = 0; i < handCount; i++) {
			discardCard(0, pre.whoseTurn, &pre, 0);
		}

		for (i = 0; i < 4; i++) {
			drawCard(pre.whoseTurn, &pre);
		}

		for (i = 0; i < pre.numPlayers; i++) {
			if (i == pre.whoseTurn) {
				continue;
			}
			
			if (pre.handCount[i] > 4) {
				handCount = pre.handCount[i];

				for (j = 0; j < handCount; j++) {
					discardCard(0, i, &pre, 0);
				}

				for (j = 0; j < 4; j++) {
					drawCard(i, &pre);
				}
			}
		}
	}

	// Print comparision errors
	printCompErrors(&pre, state);

	if (memcmp(&pre, state, sizeof(struct gameState)) != 0) {
		return -1;
	}

	return 0;
}

int main(int argc, char **argv)
{
	int i, result, handPos, choice1, choice2, counter = 0;
	struct gameState state;

	for (i = 0; i < TEST_CASES; i++) {

		// Reset variables
		handPos = 0;
		choice1 = 0;
		choice2 = 0;
		
		createGameState(&state, &handPos, &choice1, &choice2);
		result = test(&state, handPos, choice1, choice2);
		if (result == 0) {
			printf("TEST CASE #%d = PASS\n", i + 1);
			counter += 1;
		} else {
			printf("TEST CASE #%d = FAIL <------\n", i + 1);
		}
	}

	printf("PASSED CASES: %d out of %d\n", counter, TEST_CASES);
	return 0;
}